package com.yc.mybatis.core;

import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

/**
 * SqlSessionFactory
 * （1）读取配置文件获取数据库连接信息和映射文件路径
 * （）根据读取到的数据库连接信息创建好数据库连接池
 * （）根据读取到的映射文件信息，读取解析映射文件。namespace.id对应一个可执行的sql对象
 * （）提供一个返回sqlSession的方法，用来执行sql语句
 * @author 3456
 * Company 源辰
 * @date 2023年3月4日
 */
public class SqlSessionFactory {
	private InputStream is = null; // 配置文件
	//存取数据库连接信息
	private Map<String, String> dataSourceMap = new Hashtable<String, String>(); // 线程安全的
	private List<String> mappers = new Vector<String>(); // 存放映射文件路径,线程安全的
	private Map<String, MapperInfo> mapperInfos = new Hashtable<String, MapperInfo>();
	
	private ConnectionPool connectionPool; // 连接池

	public SqlSessionFactory(InputStream is) {
		this.is = is;
		init(); // 初始化方法
	}
	
	/**
	 * 初始化方法
	 */
	private void init() {
		parseConfigXml(); // 解析config.xml方法
		
//		dataSourceMap.forEach((key, val) -> {
//			System.out.println(key + " : " + val);
//		});
//		
//		mappers.forEach(System.out::println);
		
		parseMapperXml();
//		mappers.forEach((key, val) -> {
//			System.out.println(key + " : " + val);
//		});
		ConnecitonPoolFactory.create(dataSourceMap.get("driver"), dataSourceMap.get("url"),
				dataSourceMap.get("username"),dataSourceMap.get("password"));
		connectionPool = ConnecitonPoolFactory.getInstance();
	
	}

	/**
	 * 解析映射文件
	 */
	private void parseMapperXml() {
		if(mappers == null || mappers.isEmpty()) {
			return;
		}
		
		SAXReader reader = null;
		MapperInfo mapperInfo = null;
		Document doc = null;
		XPath xpath = null;
		
		String basePath = ""; // 存放namespace中的值
		String nodeName = null;
		String sql = null;
		List<Node> nodes = null;
		Element el = null;
		
		Pattern pattern = null;
		Matcher matcher = null;
		List<String> params = null;
		
		for(String mapper : mappers) { // 循环每一个映射文件
			//读取每一个映射文件
				try (InputStream iss = this.getClass().getClassLoader().getResourceAsStream(mapper)){
					if(iss == null) {
						throw new RuntimeException("映射文件" + mapper + "读取失败。。");
					}
					
					reader = new SAXReader();
					doc = reader.read(iss);
					
					basePath = doc.getRootElement().attributeValue("namespace"); // 获取根节点中的命名空间的值
					if(!StringUtil.checkNull(basePath)) {
						basePath += ".";
					}
					
					xpath = doc.createXPath("/mapper/*");
					nodes = xpath.selectNodes(doc);
					if(nodes == null || nodes.isEmpty()) {
						continue; // 读取下一个文件
					}
					
					for(Node node : nodes) {
						nodeName = node.getName().toLowerCase(); // 获取节点的名称
						System.out.println(nodeName);
						
						if(!"update".equals(nodeName) && !"insert".equals(nodeName) && !"delete".equals(nodeName) && !"select".equals(nodeName)) {
							continue;
						}
						
						mapperInfo = new MapperInfo(); // 初始化对象
						if("select".equals(nodeName)) { // 说明是查询不是更新
							mapperInfo.setUpdate(false);
						}
						
						el = (Element) node;
						mapperInfo.setResultType(el.attributeValue("resultType"));
						mapperInfo.setParameterType(el.attributeValue("parameterType"));
						sql = el.getTextTrim();
						
						pattern = Pattern.compile("[#][{]\\w+}");
						matcher = pattern.matcher(sql); // 从sql中找出符合要求的字符串
						params = new Vector<String>();
						while(matcher.find()) { // 如果还能找到符合要求的字符串
							params.add(matcher.group().replaceAll("[#{}]*", "")); // 获取每一个满足条件的字符串并替换掉里面的#{}
							//System.out.println(matcher.group());
						}
						sql = matcher.replaceAll("?"); // 将满足条件的字符串全部替换成？
						mapperInfo.setSql(sql);
						mapperInfo.setParams(params);
						mapperInfos.put(basePath + el.attributeValue("id"), mapperInfo);
					}
				} catch (IOException e) {
					e.printStackTrace();
				} catch (DocumentException e) {
					e.printStackTrace();
				}
			
			
		}
	}

	/**
	 * 解析配置文件
	 */
	private void parseConfigXml() {
		SAXReader reader = new SAXReader();
		
		if(is == null) {
			throw new RuntimeException("读取配置文件失败。。。");
		}
		
		try {
			Document doc = reader.read(is);
			
			
			XPath xpath = doc.createXPath("//dataSource/property");
			List<Node> properties = xpath.selectNodes(doc); // 到指定的文档中找对应的标签
			if(properties == null || properties.isEmpty()) {
				throw new RuntimeException("读取数据库连接信息失败。。。");
			}
			
			Element el;
			for(Node node : properties) {
				el = (Element) node;
				dataSourceMap.put(el.attributeValue("name"), el.attributeValue("value"));
			}
			
			xpath = doc.createXPath("//mappers/mapper");
			List<Node> listMappers = xpath.selectNodes(doc);
			
			if(listMappers == null || listMappers.isEmpty()) {
				return;
			}
			
			for(Node node : listMappers) {
				el = (Element) node;
				mappers.add(el.attributeValue("resource"));
			}
		
		} catch (DocumentException e) {
			e.printStackTrace();
		}finally {
			if(is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public SqlSession openSession() {
		return new SqlSession(connectionPool, mapperInfos);
	}
}
